import net from "net";
import { BinaryReader, ObjCoder } from "k-coder";
import { logger } from "../util/logger";
import { miscCfg, ScoketRegMsg } from "../util/defines";

const r = new BinaryReader();

/**
 * 封装的TcpSocket
 */
export class TcpSocket {

    socket: net.Socket;
    remoteAddress: string;
    dataMaxLen: number = miscCfg.dataMaxLen;

    private _onData: any;
    private _onClose: any;
    private _onError: any;

    constructor(socket: net.Socket) {
        socket.setNoDelay(true);
        this.socket = socket;
        this.remoteAddress = socket.remoteAddress;
    }

    /**
     * 编码消息
     * @param data 
     * @returns 
     */
    static encode(data: any) {
        return ObjCoder.encodeObj(data).end();
    }

    /**
     * 发送消息
     * @param data 
     */
    send(data: any) {
        this.socket.write(TcpSocket.encode(data));
    }

    /**
     * 发送注册消息
     * @param data 
     */
    sendReg(data: ScoketRegMsg) {
        this.send(data);
    }

    /**
     * 监听onData或onClose 重复监听会覆盖上次的
     * @param onData 
     * @param onClose 
     */
    on(onData?: (data: any) => void, onClose?: (err?: Error) => void) {
        if (onData) {
            this.off("data");
            this._onData = (buf: Buffer) => {
                if (buf.length > this.dataMaxLen) {
                    logger.error(`${this.remoteAddress}发送的数据包大小超过最大长度${this.dataMaxLen}限制,已关闭连接`, this, "onData");
                    this.close();
                    return;
                }
                let data: any;
                try {
                    r.start(buf);
                    data = ObjCoder.decodeObj(r);
                } catch (e: any) {
                    logger.error(`${this.remoteAddress}数据解析失败,已关闭连接` + e.stack, this, "onData")
                    this.close();
                    return;
                }
                onData(data);
                r.hasNext && this._onData(r.cut(r.len - r.pos)); //解决粘包问题
                r.end();
            }
            this.socket.on("data", this._onData);
        }
        if (onClose) {
            this.off("close");
            this._onClose = () => { this.off("data"); onClose(); };
            this._onError = (err: Error) => { this.off("*"); onClose(err); };
            this.socket.on("close", this._onClose);
            this.socket.on("error", this._onError);
        }
    }

    /**
     * 取消监听
     * @param event 
     */
    off(event: "*" | "data" | "close" = "*"): void {
        if ((event === "*" || event === "data")) {
            if (this._onData) {
                this.socket.off("data", this._onData);
                this._onData = null;
            }
        }
        if (event === "*" || event === "close") {
            if (this._onClose) {
                this.socket.off("close", this._onClose);
                this.socket.off("error", this._onError);
                this._onClose = null;
                this._onError = null;
            }
        }
    }

    close() {
        this.socket.end(() => {
            setTimeout(() => {
                this.socket.destroy();
            }, 1000);
        });
        this.socket.emit("close");
    }
}